package com.demo.springcache.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.springcache.entity.AclUser;
import com.demo.springcache.dao.AclUserMapper;
import com.demo.springcache.pojo.vo.AclUserVo;
import com.demo.springcache.service.AclUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 *
 * @EnableCaching：开启缓存注解功能
 * @Cacheable：在方法执行前查看是否有缓存对应的数据，如果有直接返回数据，如果没有调用方法获取数据返回，并缓存起来。
 * @CachePut：将方法的返回值放到缓存中
 * @CacheEvict：将一条或多条数据从缓存中删除。
 * @Caching：组合多个缓存注解；
 * @CacheConfig：统一配置@Cacheable中的value值
 *
 *
 * </p>
 *
 * @author jxm
 * @since 2023-12-28
 */
@Slf4j
@Service
public class AclUserServiceImpl extends ServiceImpl<AclUserMapper, AclUser> implements AclUserService {

    /**
     * @Cacheable注解
     *
     * condition 不指定相当于 true，unless 不指定相当于 false
     *  condition=false时，不读取缓存，直接执行方法体，并返回结果，同时返回结果也不放入缓存。
     *  condition=true时，读取缓存，有缓存则直接返回。无则执行方法体，同时返回结果放入缓存（如果配置了result，且要求不为空，则不会缓存结果）。
     *  unless：条件符合则不缓存，是对出参进行判断
     *    当 condition = false，一定不会缓存；
     * 　　当 condition = true，且 unless = true，不缓存；
     * 　　当 condition = true，且 unless = false，缓存；
     *
     *  注意：
     * condition 属性使用的SpEL语言只有#root和获取参数类的SpEL表达式,不能使用返回结果的#result 。
     * 所以 condition = "#result != null" 会导致所有对象都不进入缓存,每次操作都要经过数据库。
     *
     * sync：是否使用异步，默认是false. 注意：sync与unless不可以同时使用
     */
    @Cacheable(cacheNames = "user",key = "#userId",condition = "#userId>1",unless = "#result==null")
//    @Cacheable(cacheNames = "user",key = "#userId",condition = "#userId>1",sync = true)
    @Override
    public AclUser selectById(Integer userId) {
        log.info("-----------查询数据库------------");
        AclUser aclUser = this.baseMapper.selectById(userId);
        return aclUser;
    }


    @Override
    public List<AclUser> selectList(Integer userId) {
        return null;
    }

    /**
     * @CachePut
     *  与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果，而是每次都会执行该方法，
     *  并将执行结果以键值对的形式存入指定的缓存中。
     *  他所具有的属性与@Cacheable相同就不多描述。
     *  当调用updateUser方法时，每次方法都会被执行，但是因为unless属性每次都是true，所以并没有将结果缓存。当去掉unless属性，则结果会被缓存。
     */

    @CachePut(cacheNames = "user",unless = "#result!=1")
    @Override
    public int updateUser(AclUserVo vo) {
        AclUser aclUser = new AclUser();
        aclUser.setGmtModified(LocalDateTime.now());
        BeanUtils.copyProperties(vo,aclUser);
        int update = this.baseMapper.updateById(aclUser);
        return update;
    }

    /**
     * @CacheEvict
     *      清空缓存
     *      注解的方法在调用时会从缓存中移除已存储的数据。
     *  allEntries：是否清空左右缓存。默认为false
     *      当指定了allEntries为true时，Spring Cache将忽略指定的key
     *  beforeInvocation：是否在方法执行前就清空，默认为 false
     *  清除操作默认是在对应方法成功执行之后触发的，即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。
     *  使用beforeInvocation可以改变触发清除操作的时间，当我们指定该属性值为true时，Spring会在调用该方法之前清除缓存中的指定元素。
     */
    @CacheEvict(cacheNames = "user",key = "#userId",allEntries = true)
    @Override
    public int deleteUser(Integer userId) {
        return this.baseMapper.deleteById(userId);
    }
}
